﻿using Microsoft.AspNetCore.Mvc;
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using SelfService.Helpers;
using SelfService.Model.Interface;
using WalkingTec.Mvvm.Core;
using SelfService.Model.Models;
using TT;
using Microsoft.Extensions.DependencyInjection;
using SelfService.Model;
using SelfService.Model.Request;
using WalkingTec.Mvvm.Mvc;

namespace SelfService.Controllers
{
    [AuthorizeJwtWithCookie]
    public partial class SysPayController
    {
        private static object Locker = new();
        /// <summary>
        /// 获取支付二维码
        /// </summary>
        /// <param name="post"></param>
        /// <returns></returns>
        [HttpPost("GetQrCode")]
        [ActionDescription("获取支付二维码")]
        [ModelFilter]
        public async Task<Result<SysPay>> GetQrCode([FromBody] SysPay post)
        {
            try
            {
                if (post.OutOrderNo.IsNullOrWhiteSpace()) post.OutOrderNo = Guid.NewGuid().ToString("N");
                var any = await DC.Set<SysPay>().AnyAsync(e => e.OutOrderNo == post.OutOrderNo);
                if (any)
                {
                    return new Result<SysPay>
                    {
                        Code = 1,
                        Message = "商户订单号不能重复"
                    };
                }
                //查询患者
                var result = await this.CheckPatient(post.PatientId, "申请支付码");
                if (result.Code != 200)
                {
                    return new Result<SysPay>
                    {
                        Code = 1,
                        Message = result.Message
                    };
                }
                post.Patient = result.Data;
                var payType = await DC.Set<SysPayType>().FirstOrDefaultAsync(e => e.ID == post.PayTypeId);
                if (payType == null)
                {
                    return new Result<SysPay>
                    {
                        Code = 1,
                        Message = "无效的支付方式"
                    };
                }
                post.PayType = payType;
                //调用HIS接口
                IPaySystem service;
                try
                {
                    service = Wtm.ServiceProvider.GetService<IPaySystem>();
                }
                catch (Exception)
                {
                    return new Result<SysPay>()
                    {
                        Code = 1,
                        Message = "服务端没有启用该业务"
                    };
                }

                if (service == null)
                {
                    return new Result<SysPay>()
                    {
                        Code = 1,
                        Message = "服务端没有启用该业务"
                    };
                }
                var data = await service.GetQrCode(post, Wtm.LoginUserInfo);
                if (data.Code == 200)
                {
                    this.Logger($"获取支付二维码. 请求数据:{data.Request}, 返回数据:{data.Response}", ActionLogTypesEnum.Debug);
                    var pay = new SysPay();
                    pay.CopyPropertyFrom(data.Data);
                    pay.PayStatus = PayStatusEnum.支付中;
                    pay.ID = Guid.NewGuid();
                    pay.CreateBy = Wtm.LoginUserInfo.ITCode;
                    pay.CreateTime = DateTime.Now;
                    pay.UpdateBy = Wtm.LoginUserInfo.ITCode;
                    pay.UpdateTime = DateTime.Now;
                    await DC.Set<SysPay>().AddAsync(pay);
                    await DC.SaveChangesAsync();
                    this.Logger($"获取到支付二维码:{JsonConvert.SerializeObject(pay)}", ActionLogTypesEnum.Debug);
                    return new Result<SysPay>
                    {
                        Data = pay
                    };
                }
                else
                {
                    this.Logger($"获取支付二维码失败, 请求数据:{data.Request}, 返回数据:{data.Response}", ActionLogTypesEnum.Exception);
                    return new Result<SysPay>()
                    {
                        Code = 1,
                        Message = "获取支付二维码失败"
                    };
                }
            }
            catch (Exception e)
            {
                this.Logger($"获取支付二维码异常. 用户信息[{JsonConvert.SerializeObject(post)}], 异常信息: {JsonConvert.SerializeObject(e)}", ActionLogTypesEnum.Exception);
                return new Result<SysPay>()
                {
                    Code = 1,
                    Message = "获取支付二维码失败"
                };
            }
        }

        /// <summary>
        /// 扫码支付
        /// </summary>
        /// <param name="post"></param>
        /// <returns></returns>
        [HttpPost("MicroPay")]
        [ActionDescription("扫码支付")]
        [ModelFilter]
        public async Task<Result<SysPay>> MicroPay([FromBody] SysPay post)
        {
            try
            {
                if (post.OutOrderNo.IsNullOrWhiteSpace())
                {
                    return new Result<SysPay>
                    {
                        Code = 1,
                        Message = "商户订单号不能为空"
                    };
                }
                var any = await DC.Set<SysPay>().AnyAsync(e => e.OutOrderNo == post.OutOrderNo);
                if (any)
                {
                    return new Result<SysPay>
                    {
                        Code = 1,
                        Message = "商户订单号不能重复"
                    };
                }
                //查询患者
                var result = await this.CheckPatient(post.PatientId, "扫码支付");
                if (result.Code != 200)
                {
                    return new Result<SysPay>
                    {
                        Code = 1,
                        Message = result.Message
                    };
                }
                post.Patient = result.Data;
                var payType = await DC.Set<SysPayType>().FirstOrDefaultAsync(e => e.ID == post.PayTypeId);
                if (payType == null)
                {
                    return new Result<SysPay>
                    {
                        Code = 1,
                        Message = "无效的支付方式"
                    };
                }
                post.PayType = payType;
                //调用HIS接口
                IPaySystem service;
                try
                {
                    service = Wtm.ServiceProvider.GetService<IPaySystem>();
                }
                catch (Exception)
                {
                    return new Result<SysPay>()
                    {
                        Code = 1,
                        Message = "服务端没有启用该业务"
                    };
                }

                if (service == null)
                {
                    return new Result<SysPay>()
                    {
                        Code = 1,
                        Message = "服务端没有启用该业务"
                    };
                }
                var data = await service.MicroPay(post, Wtm.LoginUserInfo);
                if (data.Code == 200)
                {
                    this.Logger($"扫码支付. 请求数据:{data.Request}, 返回数据:{data.Response}", ActionLogTypesEnum.Debug);
                    var pay = new SysPay();
                    pay.CopyPropertyFrom(data.Data);
                    pay.PayStatus = PayStatusEnum.支付中;
                    pay.ID = Guid.NewGuid();
                    pay.CreateBy = Wtm.LoginUserInfo.ITCode;
                    pay.UpdateBy = Wtm.LoginUserInfo.ITCode;
                    pay.CreateTime = DateTime.Now;
                    pay.UpdateTime = DateTime.Now;
                    await DC.Set<SysPay>().AddAsync(pay);
                    await DC.SaveChangesAsync();
                    return new Result<SysPay>()
                    {
                        Data = pay
                    };
                }
                else
                {
                    this.Logger($"扫码支付失败, 请求数据:{data.Request}, 返回数据:{data.Response}", ActionLogTypesEnum.Exception);
                    return new Result<SysPay>
                    {
                        Code = 1,
                        Message = "扫码支付失败"
                    };
                }
            }
            catch (Exception e)
            {
                this.Logger($"扫码支付异常. 用户信息[{JsonConvert.SerializeObject(post)}], 异常信息: {JsonConvert.SerializeObject(e)}", ActionLogTypesEnum.Exception);
                return new Result<SysPay>
                {
                    Code = 1,
                    Message = "扫码支付失败"
                };
            }
        }
        
        /// <summary>
        /// 查询支付结果
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("GetPayResult")]
        [ActionDescription("查询支付结果")]
        public async Task<Result<SysPay>> GetPayResult([FromQuery]Guid id)
        {
            try
            {
                //查询支付订单
                if (id == Guid.Empty)
                {
                    return new Result<SysPay>
                    {
                        Code = 1,
                        Message = "支付订单不存在"
                    };
                }

                var pay = await DC.Set<SysPay>().FirstOrDefaultAsync(e => e.ID == id);
                if (pay == null)
                {
                    return new Result<SysPay>
                    {
                        Code = 1,
                        Message = "支付订单不存在"
                    };
                }

                return new Result<SysPay>
                {
                    Data = pay
                };
            }
            catch (Exception e)
            {
                this.Logger($"查询支付结果异常. 支付订单ID[{id}], 异常信息: {JsonConvert.SerializeObject(e)}", ActionLogTypesEnum.Exception);
                return new Result<SysPay>
                {
                    Code = 1,
                    Message = "查询支付结果异常"
                };
            }
        }

        /// <summary>
        /// 退款
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost("Refund")]
        [ActionDescription("退款")]
        public async Task<Result<SysPay>> Refund([FromBody] PayRefundRequest request)
        {
            try
            {
                SysPay pay;
                SysPrescription prescription = default;
                lock (Locker)
                {
                    pay = DC.Set<SysPay>().FirstOrDefault(e => e.ID == request.PayId);
                    if (pay == null)
                    {
                        return new Result<SysPay>
                        {
                            Code = 1,
                            Message = "支付订单不存在"
                        };
                    }
                    if (pay.PayStatus != PayStatusEnum.支付成功)
                    {
                        return new Result<SysPay>
                        {
                            Code = 1,
                            Message = $"当前支付不允许退款, 支付状态:{Enum.GetName(typeof(PayStatusEnum), pay.PayStatus)}"
                        };
                    }
                    
                    if (pay.RefundStatus == RefundStatusEnum.退款异常)
                    {
                        return new Result<SysPay>
                        {
                            Code = 1,
                            Message = "该订单退款异常, 请人工处理"
                        };
                    }
                    
                    if (pay.RefundStatus == RefundStatusEnum.退款中)
                    {
                        return new Result<SysPay>
                        {
                            Code = 1,
                            Message = "该订单正在退款中, 请勿重复发起"
                        };
                    }


                    
                    if (pay.UseStatus == UseStatusEnum.成功)
                    {
                        if (pay.Use == PayUseEnum.缴费)
                        {
                            //缴费退款必须提供处方ID
                            if (request.PrescriptionId.IsNullOrEmpty())
                            {
                                return new Result<SysPay>
                                {
                                    Code = 1,
                                    Message = "当前支付已经绑定处方, 请提供处方ID"
                                };
                            }
                            prescription = DC.Set<SysPrescription>().FirstOrDefault(e => e.ID == request.PrescriptionId);
                            if (prescription == null)
                            {
                                return new Result<SysPay>
                                {
                                    Code = 1,
                                    Message = "无效的处方ID"
                                };
                            }
#if !DEBUG
                            if (prescription.Status != SysOrderStatus.退款中)
                            {
                                return new Result<SysPay>
                                {
                                    Code = 1,
                                    Message = "处方状态异常"
                                };
                            }
#endif
                            if (prescription.PayId != request.PayId)
                            {
                                return new Result<SysPay>
                                {
                                    Code = 1,
                                    Message = "处方状态异常"
                                };
                            }
                        }
                        else
                        {
                            //非缴费退款, 只有管理员可以操作已经使用的订单
                            if (Wtm.LoginUserInfo.ITCode != "admin")
                            {
                                if (pay.UseStatus == UseStatusEnum.成功)
                                {
                                    return new Result<SysPay>
                                    {
                                        Code = 1,
                                        Message = $"该订单无法已经用作{Enum.GetName(typeof(UseStatusEnum), pay.Use)}, 请人工处理"
                                    };
                                }
                            }
                        }
                    }
                    pay.RefundStatus = RefundStatusEnum.退款中;
                    pay.UpdateBy = Wtm.LoginUserInfo.ITCode;
                    pay.UpdateTime = DateTime.Now;
                    DC.SaveChanges();
                }
                
                //调用HIS接口
                IPaySystem service;
                try
                {
                    service = Wtm.ServiceProvider.GetService<IPaySystem>();
                }
                catch (Exception)
                {
                    return new Result<SysPay>()
                    {
                        Code = 1,
                        Message = "服务端没有启用该业务"
                    };
                }
                if (service == null)
                {
                    return new Result<SysPay>()
                    {
                        Code = 1,
                        Message = "服务端没有启用该业务"
                    };
                }
                var result = await service.Refund(pay);
                if (result != null)
                {
                    this.Logger($"发起退款. 请求数据:{result.Request}, 返回数据:{result.Response}", ActionLogTypesEnum.Job);
                    if (result.Code == 200)
                    {
                        pay.RefundId = result.Data.RefundId;
                        pay.RefundNo = result.Data.RefundNo;
                        pay.RefundStatus = RefundStatusEnum.退款完成;
                        pay.UpdateTime = DateTime.Now;
                        if (prescription != null)
                        {
                            prescription.Status = SysOrderStatus.退款完成;
                            prescription.UpdateTime = DateTime.Now;
                        }
                        await DC.SaveChangesAsync();
                        return new Result<SysPay>()
                        {
                            Data = pay
                        };
                    }
                    else if (result.Code == 3)
                    {
                        pay.RefundId = result.Data.RefundId;
                        pay.RefundStatus = RefundStatusEnum.退款失败;
                        pay.UpdateTime = DateTime.Now;
                        if (prescription != null)
                        {
                            prescription.Status = SysOrderStatus.退款失败;
                            prescription.UpdateTime = DateTime.Now;
                        }
                        await DC.SaveChangesAsync();
                        return new Result<SysPay>
                        {
                            Data = pay
                        };
                    }else if (result.Code == 2)
                    {
                        pay.RefundId = result.Data.RefundId;
                        await DC.SaveChangesAsync();
                        return new Result<SysPay>()
                        {
                            Data = pay
                        };
                    }
                    else
                    {
                        pay.RefundStatus = RefundStatusEnum.退款失败;
                        pay.UpdateTime = DateTime.Now;
                        if (prescription != null)
                        {
                            prescription.Status = SysOrderStatus.退款失败;
                            prescription.UpdateTime = DateTime.Now;
                        }
                        await DC.SaveChangesAsync();
                        return new Result<SysPay>
                        {
                            Code = 1,
                            Message = $"发起退款失败, {result.Message}"
                        };
                    }
                }
                else
                {
                    pay.RefundStatus = RefundStatusEnum.退款失败;
                    pay.UpdateTime = DateTime.Now;
                    await DC.SaveChangesAsync();
                    return new Result<SysPay>
                    {
                        Code = 1,
                        Message = "发起退款失败, 支付系统返回数据为空"
                    };
                }
            }
            catch (Exception e)
            {
                this.Logger($"发起退款异常. 请求信息:{JsonConvert.SerializeObject(request)}, 异常信息: {JsonConvert.SerializeObject(e)}", ActionLogTypesEnum.Exception);
                return new Result<SysPay>
                {
                    Code = 1,
                    Message = "发起退款异常"
                };
            }
        }
        
        [ActionDescription("充值")]
        [HttpPost("AddCredit")]
        [ModelFilter]
        public Result<SysPatient> AddCredit([FromBody] AddCreditRequest request)
        {
            lock (Locker)
            {
                try
                {
                    var pay = DC.Set<SysPay>().Include(e => e.PayType).FirstOrDefault(e => e.ID == request.PayId);
                    
                    if (pay == null)
                    {
                        this.Logger($"检测到不存在的PayId, 请检查是否有入侵行为, 请求信息:{JsonConvert.SerializeObject(request)}", ActionLogTypesEnum.Exception);
                        return new Result<SysPatient>()
                        {
                            Code = 1,
                            Message = "不存在的支付记录"
                        };
                    }
                    
                    if (pay.PayStatus != PayStatusEnum.支付成功)
                    {
                        this.Logger($"检测到未支付的订单在尝试完成缴费操作, 请求信息:{JsonConvert.SerializeObject(request)}", ActionLogTypesEnum.Exception);
                        return new Result<SysPatient>()
                        {
                            Code = 1,
                            Message = "订单尚未支付"
                        };
                    }

                    if (pay.Use != PayUseEnum.门诊充值)
                    {
                        this.Logger($"检测到非门诊充值的支付记录在尝试充值, 请求信息:{JsonConvert.SerializeObject(request)}", ActionLogTypesEnum.Exception);
                        return new Result<SysPatient>()
                        {
                            Code = 1,
                            Message = "该支付记录无法用于充值"
                        };
                    }

                    if (pay.UseStatus == UseStatusEnum.成功)
                    {
                        this.Logger($"检测已经使用的支付记录在尝试充值, 请求信息:{JsonConvert.SerializeObject(request)}", ActionLogTypesEnum.Exception);
                        return new Result<SysPatient>()
                        {
                            Code = 1,
                            Message = "该支付记录已经使用"
                        };
                    }

                    //查询患者
                    var result = this.CheckPatient(request.PatientId, "缴费").Result;
                    if (result.Code != 200)
                    {
                        return new Result<SysPatient>()
                        {
                            Code = 1,
                            Message = result.Message
                        };
                    }

                    var patient = result.Data;
                    //调用HIS接口
                    IHisOrder service;
                    try
                    {
                        service = Wtm.ServiceProvider.GetService<IHisOrder>();
                    }
                    catch (Exception)
                    {
                        return new Result<SysPatient>()
                        {
                            Code = 1,
                            Message = "服务端没有启用该业务"
                        };
                    }

                    if (service == null)
                    {
                        return new Result<SysPatient>()
                        {
                            Code = 1,
                            Message = "服务端没有启用该业务"
                        };
                    }

                    var data = service.AddCredit(pay, patient).Result;
                    if (data.Code == 200)
                    {
                        pay.UseStatus = UseStatusEnum.成功;
                        pay.UpdateBy = Wtm.LoginUserInfo.ITCode;
                        pay.UpdateTime = DateTime.Now;
                        DC.SaveChanges();
                        this.Logger($"充值成功, 请求数据:{data.Request}, 返回数据:{data.Response}", ActionLogTypesEnum.Debug);
                        return new Result<SysPatient>();
                    }
                    else
                    {
                        pay.UseStatus = UseStatusEnum.失败;
                        pay.UpdateBy = Wtm.LoginUserInfo.ITCode;
                        pay.UpdateTime = DateTime.Now;
                        DC.SaveChanges();
                        this.Logger($"充值失败, 请求数据:{data.Request}, 返回数据:{data.Response}", ActionLogTypesEnum.Exception);
                        return new Result<SysPatient>()
                        {
                            Code = 1,
                            Message = data.Message.IsNullOrWhiteSpace() ? "充值失败" : data.Message
                        };
                    }
                }
                catch (Exception e)
                {
                    this.Logger($"缴费异常. 请求信息:{JsonConvert.SerializeObject(request)}, 异常信息: {JsonConvert.SerializeObject(e)}", ActionLogTypesEnum.Exception);
                    return new Result<SysPatient>()
                    {
                        Code = 1,
                        Message = "充值异常, 请联系工作人员"
                    };
                }
            }

        }
        
        public class AddCreditRequest
        {
            [NotEmpty]
            public Guid PatientId { get; set; }

            [NotEmpty]
            public Guid PayId { get; set; }
        }
    }
}
